﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace SwitchDetect
{
    public class InputData
    {
        public Dictionary<int, Day> AllDays = new Dictionary<int, Day>();
        public Dictionary<int, Session> AllSessions = new Dictionary<int, Session>();
        public Dictionary<int, User> AllUsers = new Dictionary<int, User>();
        public Dictionary<int, SearchQuery> AllQueries = new Dictionary<int, SearchQuery>(); 
        public Dictionary<int, Document> AllDocuments = new Dictionary<int, Document>(); 

        public static InputData ReadData(string filename, int sessionCount = -1)
        {
            var input = new InputData();
            using(var sr = new StreamReader(filename))
            {
                Session session = null;
                SearchResult searchResult = null;
                Click click = null;
                int count = 0;
                while(!sr.EndOfStream && count!=sessionCount)
                {
                    var values = sr.ReadLine().Split('\t');
                    int sessionId = int.Parse(values[0]);
                    int time = int.Parse(values[1]);
                    switch (values[2])
                    {
                        case "M":
                            count++;
                            int userId = int.Parse(values[3]);
                            session = new Session();
                            input.AllSessions[sessionId] = session;
                            session.Id = sessionId;
                            session.Day = input.GetOrGreateDay(time);
                            session.SwitchType = values.Length<5 ? SwitchType.None : ParseSwitchType(values[4]);
                            session.User = input.GetOrGreateUser(userId);
                            session.Day.Sessions.Add(session);
                            session.User.Sessions.Add(session);
                            searchResult = null;
                            break;
                        case "Q":
                            if (sessionId != session.Id) throw new ApplicationException("Incorrect data");
                            int resultId = int.Parse(values[3]);
                            int queryId = int.Parse(values[4]);
                            searchResult = new SearchResult();
                            session.SearchResults[resultId] = searchResult;
                            searchResult.LocalId = resultId;
                            searchResult.TimePassed = time;
                            searchResult.Session = session;
                            searchResult.Query = input.GetOrGreateQuery(queryId);
                            for (int i = 5; i < values.Length; i++)
                            {
                                int documentId = int.Parse(values[i]);
                                searchResult.Documents.Add(input.GetOrGreateDocument(documentId));
                            }
                            click = null;
                            break;
                        case "C":
                            if (sessionId != session.Id) throw new ApplicationException("Incorrect data");
                            var searchResultId = int.Parse(values[3]);
                            int docId = int.Parse(values[4]);
                            click = new Click();
                            var sResult = session.SearchResults[searchResultId];
                            sResult.Clicks.Add(click);
                            click.TimePassed = time;
                            click.SearchResult = sResult;
                            click.Document = input.GetOrGreateDocument(docId);
                            break;
                        case "S":
                            if (sessionId != session.Id) throw new ApplicationException("Incorrect data");
                            if (click != null) click.WasSwitch = true;
                            else searchResult.WasSwitch = true;
                            break;
                        default:
                            throw new ApplicationException("Incorrect data");
                    }
                }
            }
            return input;
        }

        private User GetOrGreateUser(int id)
        {
            if (AllUsers.ContainsKey(id)) return AllUsers[id];
            var user = new User();
            AllUsers[id] = user;
            user.Id = id;
            return user;
        }

        private SearchQuery GetOrGreateQuery(int id)
        {
            if (AllQueries.ContainsKey(id)) return AllQueries[id];
            var query = new SearchQuery();
            AllQueries[id] = query;
            query.Id = id;
            return query;
        }

        private Day GetOrGreateDay(int id)
        {
            if (AllDays.ContainsKey(id)) return AllDays[id];
            var day = new Day();
            AllDays[id] = day;
            day.Number = id;
            return day;
        }

        private Document GetOrGreateDocument(int id)
        {
            if (AllDocuments.ContainsKey(id)) return AllDocuments[id];
            var document = new Document();
            AllDocuments[id] = document;
            document.Id = id;
            return document;
        }

        private static SwitchType ParseSwitchType(string s)
        {
            switch (s)
            {
                case "P":
                    return SwitchType.SearchResult;
                case "B":
                    return SwitchType.Toolbar;
                case "H":
                    return SwitchType.Both;
                case "N":
                    return SwitchType.None;
                default:
                    throw new ApplicationException("Incorrect data");
            }
        }
    }
}
